@using OrchardCore.ResourceManagement
@using Lombiq.DataTables.Services
@using System.Text.Json

@inject IEnumerable<IDataTableDataProvider> Providers

@inject IResourceManager ResourceManager

@{
    var viewModel = Model.ViewModel as DataTableDefinitionViewModel ?? new DataTableDefinitionViewModel();

    var pageSize = viewModel.PageSize ?? Site.PageSize;
    var skip = viewModel.Skip ?? 0;

    string queryId = viewModel.QueryId ?? Model.QueryId?.ToString() ?? "";
    string dataProvider = viewModel.DataProvider ?? Model.Provider?.ToString() ?? "";
    var columnsDefinition = viewModel.ColumnsDefinition ?? await Providers
        .Single(provider => provider.GetType().Name == dataProvider)
        .GetColumnsDefinitionAsync(queryId);
    var columns = columnsDefinition?.Columns.ToList() ?? new List<DataTableColumnDefinition>();
    var childRowsEnabled = viewModel.ChildRowsEnabled;
    var progressiveLoadingEnabled = viewModel.ProgressiveLoadingEnabled;
    var queryStringParametersLocalStorageKey = viewModel.QueryStringParametersLocalStorageKey ?? "";
    var dataTableId = string.IsNullOrEmpty(viewModel.DataTableId) ? ElementNames.DataTableElementName : viewModel.DataTableId;
    var dataTableCssClasses = string.IsNullOrEmpty(viewModel.DataTableCssClasses) ? "" : viewModel.DataTableCssClasses;

    var defaultSortingColumnIndex = Math.Max(
        0, Math.Max(columns.FindIndex(column => column.Orderable), columns.FindIndex(column => column.Name == columnsDefinition?.DefaultSortingColumnName)));

    var defaultSortingDirection = columnsDefinition?.DefaultSortingDirection ?? SortingDirection.Ascending;
    var defaultSortingDirectionValue = defaultSortingDirection == SortingDirection.Ascending ? "asc" : "desc";

    var rowsApiUrl = Url.Action(nameof(RowsController.Get), typeof(RowsController).ControllerName(), new { FeatureIds.Area });
    var childRowApiUrl = Url.Action(nameof(ChildRowsController.Get), typeof(ChildRowsController).ControllerName(), new { FeatureIds.Area });
    var exportApiUrl = Url.Action(nameof(RowsController.Export), typeof(RowsController).ControllerName(), new { FeatureIds.Area });

    const string rowElementWithChildRowVisibleModifier = ElementNames.DataTableRowElementName + "_childRowVisible";
    const string childRowElementName = ElementNames.DataTableElementName + "__childRow";
    const string toggleChildRowButtonElementName = ElementNames.DataTableElementName + "__toggleChildRowButton";
    const string templatesElementName = ElementNames.DataTableElementName + "__templates";
    const string errorsElementName = ElementNames.DataTableElementName + "__errors";

    const string templatePlaceholder = "{{data}}";

    ResourceManager.RegisterResource("script", ResourceNames.LombiqDataTables).AtFoot();
    ResourceManager.RegisterResource("script", ResourceNames.DataTables.Bootstrap5Buttons).AtFoot();
    ResourceManager.RegisterResource("stylesheet", ResourceNames.DataTables.Bootstrap5);
    ResourceManager.RegisterResource("stylesheet", ResourceNames.DataTables.Bootstrap5Buttons);

    var hasViewAction = viewModel.AdditionalDatatableOptions?["viewAction"].GetValueKind() == JsonValueKind.True;

    var defaultOrder = new[] { new[] { defaultSortingColumnIndex.ToString(), defaultSortingDirectionValue } };
    var dataTablesOptions = new Dictionary<string, object> { ["order"] = defaultOrder };
    if (pageSize > 0) { dataTablesOptions["pageLength"] = pageSize; }
    if (viewModel.AdditionalDatatableOptions is { } options)
    {
        foreach (var (key, value) in options)
        {
            dataTablesOptions[key] = value;
        }
    }

    var pluginOptions = new Dictionary<string, object>
    {
        ["rowClassName"] = ElementNames.DataTableRowElementName,
        ["dataProvider"] = dataProvider,
        ["rowsApiUrl"] = rowsApiUrl,
        ["export"] = new
        {
            textAll = T["Export All"].Value,
            textVisible = T["Export Visible"].Value,
            api = exportApiUrl,
        },
        ["texts"] = new
        {
            yes = T["Yes"].Value,
            no = T["No"].Value,
        },
        ["errorsSelector"] = '.' + errorsElementName,
        ["serverSidePagingEnabled"] = !progressiveLoadingEnabled,
        ["queryStringParametersLocalStorageKey"] = queryStringParametersLocalStorageKey,
        ["progressiveLoadingOptions"] = new
        {
            progressiveLoadingEnabled,
            skip,
            batchSize = pageSize,
        },
        ["childRowOptions"] = new
        {
            childRowsEnabled,
            asyncLoading = true,
            apiUrl = childRowApiUrl,
            childRowClassName = childRowElementName,
            toggleChildRowButtonClassName = toggleChildRowButtonElementName,
            childRowVisibleClassName = rowElementWithChildRowVisibleModifier,
        },
        ["culture"] = Orchard.CultureName(),
    };
    if (!string.IsNullOrWhiteSpace(queryId)) { pluginOptions["queryId"] = queryId; }
}

@await DisplayAsync(await New.Lombiq_DataTable_Resources(ViewModel: viewModel))

<div class="@ElementNames.DataTableWrapperDefaultElementName @dataTableCssClasses" data-draw="0">
    @* We have no control over the HTML structure generated by DataTables (and it contains some deprecated attributes
       for the sake of backwards compatibility and other discouraged characteristics like empty ID attributes) so we
       have to disable HTML validation within the table like this. *@
    <!-- [html-validate-disable no-deprecated-attr, prefer-native-element, attribute-allowed-values, valid-id, element-permitted-order] -->
    @await DisplayAsync(await New.Lombiq_DataTable_Table(
        ViewModel: new DataTableDataViewModel
        {
            DataTableId = dataTableId,
            ColumnsDefinition = columnsDefinition,
            ChildRowsEnabled = childRowsEnabled,
        },
        DataTableId: dataTableId,
        Columns: columns,
        ChildRowsEnabled: childRowsEnabled))
    <!-- [html-validate-enable no-deprecated-attr, prefer-native-element, attribute-allowed-values, valid-id, element-permitted-order] -->
    <div class="@errorsElementName" style="display: none;"></div>
    <div class="@templatesElementName" hidden>
        <div data-id="actions" class="btn-group">
            <button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                @T["Actions"]
            </button>

            @{
                var values = new
                {
                    area = "OrchardCore.Contents",
                    contentItemId = templatePlaceholder,
                    returnUrl = FullRequestPath,
                };
            }
            <div class="dropdown-menu dropdown-menu-right">
                <a class="dropdown-item btn-sm" href="@Url.Action("Edit", "Admin", values)">@T["Edit"]</a>
                @if (hasViewAction)
                {
                    <a class="dropdown-item btn-sm" href="@Url.Action("Display", "Item", values)">@T["View"]</a>
                }
                <a class="dropdown-item btn-sm" href="@Url.Action("Remove", "Admin", values)" itemprop="RemoveUrl UnsafeUrl" data-title="@T["Delete"]" data-message="@T["Are you sure you want to delete this content item?"]">@T["Delete"]</a>
            </div>
        </div>
    </div>
</div>

<script depends-on="@ResourceNames.LombiqDataTables" at="Foot">
    jQuery(function ($) {
        const templates = {};
        $(".@templatesElementName > div[data-id]").each(function(index, element) {
            templates[element.getAttribute('data-id')] = element.innerHTML.replace(/%7B%7Bdata%7D%7D/g, '@templatePlaceholder');
            element.parentElement.removeChild(element);
        });

        const pluginOptions = @Json.Serialize(pluginOptions);
        pluginOptions.dataTablesOptions = $.extend(
            { },
            window.dataTableResources.options,
            { templates },
            @Json.Serialize(dataTablesOptions));

        const plugin = $("#@dataTableId").lombiq_DataTables(pluginOptions);

        window.dataTableResources.created(
                $("#@dataTableId").parents(".@ElementNames.DataTableWrapperDefaultElementName"),
                plugin,
                pluginOptions.dataTablesOptions);
    });
</script>
